/*
 *
 * Copyright (C) 2008 Ed Hong
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


#include "Characteristics.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int is_on_border(const SubbandBits *sb, int r, int c) {
  return (r  == 0 ) || (c == 0) | (r == sb->num_rows-1) || (c == sb->num_cols-1);
}
int subband_orientation(int s) {
  return (s==0)?0:(1+(s+2)%3);
}

int is_sign(const SubbandBits *sb, int r, int c, int bp) {
  return bp==-1;
}

int is_sig(const SubbandBits *sb, int r, int c, int bp) {
  if (bp==-1) return 0;
  return bp <= sb->coeff[r][c].significance_level;
}

int refine_level(const SubbandBits *sb, int r, int c, int bp) {
  if ((bp <= sb->coeff[r][c].significance_level)) return 0;
  return bp - sb->coeff[r][c].significance_level ;
}
int is_refine(const SubbandBits *sb, int r, int c, int bp) {
  return refine_level(sb,r,c,bp)>0;
}
int bitplane_num(const SubbandBits *sb, int r, int c, int bp) {
  if (bp==-1) return sb->coeff[r][c].significance_level;
  else return bp;
}

int sig_h(const NeighborSignificance *ns){  
  switch(ns->so) {
  case 0: case 1: case 3: return (ns->e >= 1) + (ns->w >= 1);
  case 2: return (ns->n >= 1) + (ns->s >= 1);
  default:  return -1; // error value
  }
}
int sig_v(const NeighborSignificance *ns) {
  switch(ns->so) {
  case 0: case 1: case 3: return (ns->n >= 1) + (ns->s >= 1);
  case 2: return (ns->e >= 1) + (ns->w >= 1);
  default:   return -1;  // error value
  }
}
int sig_d(const NeighborSignificance *ns) {
  return (ns->nw >=1) + (ns->ne >= 1) + (ns->sw >= 1) + (ns->se >= 1);
}
int sig_label(const NeighborSignificance *ns){
  int sig_vh;
  switch(ns->so) {
  case 0: case 1: case 2: 
    if ((sig_h(ns) + sig_v(ns))==0) {
      return (sig_d(ns)>=1)+(sig_d(ns)>1);
    }
    else if (sig_h(ns)==0) // && (sig_v(ns) !=0)
      return sig_v(ns)+2;
    else if (sig_h(ns) == 1)
      return (sig_v(ns)>0)?7:(5 + (sig_d(ns)>0));
    else return 8;
  case 3:
    sig_vh = sig_v(ns) + sig_h(ns);
    if (sig_d(ns) < 2)
      return sig_d(ns)*3+(sig_vh>=1) + (sig_vh>=2);
    else if (sig_d(ns)==2)
      return 6 + (sig_vh>0);
    else return 8;
  default:
    printf("sig_label: error! unknown subband orientation of %d.\n", ns->so);
    return -1; // error value. 
  }
}
int sign_hs(const NeighborSigns *ns) {
  switch(ns->so) {
  case 0: case 1: case 3: 
    return (ns->e == ns->w)? (ns->e):(ns->e+ns->w) ;
  case 2: 
    return (ns->n == ns->s)? (ns->n):(ns->n+ns->s) ;
  default: 
    printf("sign_vs: error! unknown subband orientation of %d.\n", ns->so);
    return -2; // error value
  }
}
int sign_vs(const NeighborSigns *ns) {
  switch(ns->so) {
  case 0: case 1: case 3: 
    return (ns->n == ns->s)? (ns->n):(ns->n+ns->s) ;
  case 2: 
    return (ns->e == ns->w)? (ns->e):(ns->e+ns->w) ;
  default:
    printf("sign_vs: error! unknown subband orientation of %d.\n", ns->so);
    return -2; // error value
  }
}
int sign_label(const NeighborSigns *ns){
  if (sign_hs(ns) == sign_vs(ns)) {
    return 4 * sign_hs(ns);
  }
  else if (sign_hs(ns) +sign_vs(ns)==0) {
    return 2 * sign_hs(ns);
  }
  else if (sign_hs(ns)==0) {
    return -sign_vs(ns);
  }
  else {
    return 3*sign_hs(ns);
  }
}

int refine_label(const NeighborSignificance *ns, const SubbandBits *sb, int r, int c,  int bp){
  //  if (is_refine(sb, r, c, bp)) {
    if (refine_level(sb, r, c, bp)==1) return 2;
    else return (sig_h(ns) + sig_v(ns) > 0);
    // } else  return -1;  
}

int sig_count(const NeighborSignificance *ns) {
  return (ns->nw>0) + (ns->n>0) + (ns->ne>0) + (ns->w>0) +
    (ns->se>0) + (ns->s>0) + (ns->sw>0) + (ns->e>0) +
    (ns->parent>0) + (ns->children>0) + (ns->sl1>0) + (ns->sl2>0);
}


// bp bitplane; does not work for bp==-1.
static int getNeighborSignificance(const SubbandBits *sb, int r, int c, int bp) {
  if (coeff_exists(sb,r,c)) {
    int siglevel = sb->coeff[r][c].significance_level;
    int currbitplane = sb->coeff[r][c].currbitplane;
    if (siglevel >= currbitplane) 
      return -1; // not yet known in decoder  that this guy is significant. 
    else if (siglevel < bp  ) return 2;
    else if (siglevel == bp && (currbitplane>bp)) return 1;
    else return -1; 
  }
  else return 0;
}



static void computeNeighborSignificance8Adj(const SubbandComponent *sc, int r, int c, int s, int bp, NeighborSignificance *ns) {
    ns->nw = getNeighborSignificance(&(sc->sub[s]),r-1,c-1,bp);
    ns->n = getNeighborSignificance(&(sc->sub[s]),r-1,c,bp);
    ns->ne = getNeighborSignificance(&(sc->sub[s]),r-1,c+1,bp);
    ns->w = getNeighborSignificance(&(sc->sub[s]),r,c-1,bp);
    ns->e = getNeighborSignificance(&(sc->sub[s]),r,c+1,bp);
    ns->sw = getNeighborSignificance(&(sc->sub[s]),r+1,c-1,bp);
    ns->s = getNeighborSignificance(&(sc->sub[s]),r+1,c,bp);
    ns->se = getNeighborSignificance(&(sc->sub[s]),r+1,c+1,bp);

}

int sig_count_8Neighb(const SubbandComponent *sc, int r, int c, int s, int bp) {
   NeighborSignificance ns; 
   computeNeighborSignificance8Adj(sc,r,c,s,bp,&ns);
   return (ns.nw>0) + (ns.n>0) + (ns.ne>0) + (ns.w>0) +
    (ns.se>0) + (ns.s>0) + (ns.sw>0) + (ns.e>0);
}

static void computeNeighborSignificanceChildren(const SubbandComponent *sc, int r, int c, int s, int bp, NeighborSignificance *ns) {

  if (num_children(sc, r, c, s) == 0) {
    ns->descendants = 0;
    ns->children = 0;
  }
  else {
    if (sc->sub[s].coeff[r][c].descendant_minsiglevel  < bp )
      ns->descendants = 2; // Now accurate for sorting; minsiglevel computed on the fly. 
    else if (sc->sub[s].coeff[r][c].descendant_minsiglevel  ==bp)
      ns->descendants = 1; // can only happen if we are sorting..
    else ns->descendants = -1;

    int childsub, childr, childc;
    computeChild(s,r,c,&childsub, &childr, &childc);
    
    ns->children = 0;
    int result;
    result = getNeighborSignificance(&(sc->sub[childsub]),childr+1,childc+1,bp);
    ns->children = (ns->children < result)? result : ns->children;
    result = getNeighborSignificance(&(sc->sub[childsub]),childr,childc+1,bp);
    ns->children = (ns->children < result)? result : ns->children;
    result = getNeighborSignificance(&(sc->sub[childsub]),childr+1,childc,bp);
    ns->children = (ns->children < result)? result : ns->children;
    result = getNeighborSignificance(&(sc->sub[childsub]),childr,childc,bp);
    ns->children = (ns->children < result)? result : ns->children;

    if (ns->children ==0) ns->children = -1; // insiginificant. 
  } 
}

static void computeNeighborSignificanceSubbandNeighbor(const SubbandComponent *sc, int r, int c, int s, int bp, NeighborSignificance *ns)
{
  // LL subband.
  if (s==0) {
    ns->sl1 = 0;
    ns->sl2 = 0;
  }
  else { //spatially collocated neighbor at same subband level. 
    if (s%3 == 1) {
      ns->sl1 = getNeighborSignificance(&(sc->sub[s+1]),r,c,bp);
      ns->sl2 = getNeighborSignificance(&(sc->sub[s+2]),r,c,bp);
    }
    else if (s%3 ==2) {
      ns->sl1 = getNeighborSignificance(&(sc->sub[s-1]),r,c,bp);
      ns->sl2 = getNeighborSignificance(&(sc->sub[s+1]),r,c,bp);
    }
    else {
      ns->sl1 = getNeighborSignificance(&(sc->sub[s-2]),r,c,bp);
      ns->sl2 = getNeighborSignificance(&(sc->sub[s-1]),r,c,bp);
    }  
  }
}

static void computeNeighborSignificanceParent(const SubbandComponent *sc, int r, int c, int s, int bp, NeighborSignificance *ns) {
  int psub, pr, pc;
  computeParent(s,r,c,&psub, &pr, &pc);
  if (coeff_exists(&(sc->sub[psub]),pr, pc))
      ns->parent = getNeighborSignificance(&(sc->sub[psub]),pr,pc,bp);
  else ns->parent = 0;
  
}
void computeNeighborSignificance(const SubbandComponent *sc, int r, int c, int s, int bp, NeighborSignificance *ns) {
  ns->so = subband_orientation(s);
  if (bp==-1) {
    bp = sc->sub[s].coeff[r][c].significance_level;
  }
 if (bp != sc->sub[s].coeff[r][c].currbitplane) {
   printf("computeNeighborSignificance: Error, currbitplane %d != bp %d\n", 
	  sc->sub[s].coeff[r][c].currbitplane, bp);
 }

  computeNeighborSignificance8Adj(sc,r,c,s,bp,ns);
  computeNeighborSignificanceSubbandNeighbor(sc,r,c,s,bp,ns);
  computeNeighborSignificanceParent(sc,r,c,s,bp,ns);
  computeNeighborSignificanceChildren(sc,r,c,s,bp,ns);
}


// bp bitplane, precedes == boolean value, does neighbor precede me? 
static int getNeighborSigns(const SubbandBits *sb, int r, int c, int bp) {
  if (coeff_exists(sb,r,c)) {
    int siglevel = sb->coeff[r][c].significance_level;
    int currbitplane = sb->coeff[r][c].currbitplane;
    if (currbitplane <= siglevel)
      return 0;
    else if ((siglevel < bp) || ((siglevel==bp)&&
			    (currbitplane > bp))) return sb->coeff[r][c].sign;
    else return 0;
  }
  else return 0;
}

void computeNeighborSigns(const SubbandComponent *sc, int r, int c, int s, int bp, NeighborSigns *ns) {
  ns->so = subband_orientation(s);
  if (bp==-1) {
    bp = sc->sub[s].coeff[r][c].significance_level;
  }
  ns->n = getNeighborSigns(&(sc->sub[s]), r-1, c, bp);
  ns->w = getNeighborSigns(&(sc->sub[s]), r, c-1, bp);
  ns->e = getNeighborSigns(&(sc->sub[s]), r, c+1, bp);
  ns->s = getNeighborSigns(&(sc->sub[s]), r+1, c, bp);
}


int checkflag(int x, const unsigned long long *flags) {
  if (x < 64) 
    return (flags[0] & (1LL<<x))>0;
  else
    return (flags[1] & (1LL<<(x-64)))>0;
}

void addflag(int x, unsigned long long *flags) {
  if (AllC[x].name == NULL) {
    printf("addflag: error, uninitialized characteristic %d", x);
    exit(1);
  }
  if (x < 64) 
    flags[0] |= (1LL<<x);
  else
    flags[1] |= (1LL << (x-64));
}


void removeflag(int x, unsigned long long *flags) {
  if (AllC[x].name == NULL) {
    printf("removeflag: error, uninitialized characteristic %d", x);
    exit(1);
  }
  if (x < 64) 
    flags[0] &= (~(1LL<<x));
  else
    flags[1] &= (~(1LL << (x-64)));
}

int addColorCharacteristicSet(int ColorCharacteristicType, unsigned long long *outputflags)  {
  switch (ColorCharacteristicType) {
  case 0: //all color flags
    addflag(NBITVAL_COMP0, outputflags);
    addflag(NBITVAL_COMP1, outputflags);
    addflag(NBITVAL_COMP2, outputflags);// purposely fall through
   case 1: // nsig_comp color flags
    addflag(NSIG_COMP0, outputflags);
    addflag(NSIG_COMP1, outputflags);
    addflag(NSIG_COMP2, outputflags); // purposely fall through
   case 2: // component_num color flags
    addflag(COMPONENT_NUM, outputflags);
    return 0;
  default:
   QccErrorAddMessage("(addColorCharacteristicSet): Unsupported color characteristic type %d", ColorCharacteristicType);
   return (1);   
  }  
}

int getCharacteristicSet(int CharacteristicType, unsigned long long *outputflags)  {
  outputflags[0] = 0;
  outputflags[1] = 0;
  switch (CharacteristicType) {
  case 0: // simple set of 4. 
    addflag(IS_SIGN, outputflags);
    addflag(IS_SIG, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    addflag(NSIG_N_01, outputflags);
    return 0;
  case 2: // add debugging info for set 1. 
    addflag(SUBBAND_ROW, outputflags);
    addflag(SUBBAND_COL, outputflags);    // purposely continue..
  case 1:  // all basic computation flags. 
    addflag(IS_SIGN, outputflags);
    addflag(IS_SIG, outputflags);
    addflag(IS_ON_BORDER, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    addflag(SUBBAND_NUM, outputflags);
    addflag(SUBBAND_ORIENTATION, outputflags);
    addflag(REFINE_LEVEL, outputflags);
    addflag(NSIG_NW, outputflags);
    addflag(NSIG_N, outputflags);
    addflag(NSIG_NE, outputflags);
    addflag(NSIG_N, outputflags);
    addflag(NSIG_W, outputflags);
    addflag(NSIG_E, outputflags); 
    addflag(NSIG_SW, outputflags);
    addflag(NSIG_S, outputflags);
    addflag(NSIG_SE, outputflags);
    addflag(NSIG_PARENT, outputflags);
    addflag(NSIG_CHILDREN, outputflags);
    addflag(NSIG_DESCENDANTS, outputflags);
    addflag(NSIG_PARENT, outputflags);
    addflag(NSIG_SL1, outputflags);
    addflag(NSIG_SL2, outputflags);
    addflag(NSIGN_N, outputflags);
    addflag(NSIGN_S, outputflags);
    addflag(NSIGN_E, outputflags);
    addflag(NSIGN_W, outputflags);
    return 0;
  case 4: // add debugging info for set 3, then fall through
    addflag(SUBBAND_ROW, outputflags);
    addflag(SUBBAND_COL, outputflags);    // purposely continue..
    addflag(SUBBAND_NUM, outputflags);
  case 3: // set 3: characteristics computed based on base characteristics
    addflag(BITPLANE_NUM, outputflags);
    addflag(SIG_H, outputflags);
    addflag(SIG_V, outputflags);
    addflag(SIG_D, outputflags);
    addflag(SIG_LABEL, outputflags);
    addflag(SIGN_HS, outputflags);
    addflag(SIGN_VS, outputflags);
    addflag(SIGN_LABEL, outputflags);
    addflag(REFINE_LABEL, outputflags);
    addflag(SIG_COUNT, outputflags);
    addflag(SIG_COUNT_GTW, outputflags);
    return 0;
  case 5: //JPEG2k/EBCOT set
    addflag(IS_SIGN, outputflags);
    addflag(IS_SIG, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    addflag(SIG_LABEL, outputflags);
    addflag(SIGN_LABEL, outputflags);
    addflag(REFINE_LABEL, outputflags);
    return 0;
  case 6: // GTW-like set
    addflag(IS_SIG, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    addflag(REVERSE_SUBBAND_LEVEL, outputflags);
    addflag(SIG_COUNT_GTW, outputflags);
    return 0;
  case 7: // everything set
    addflag(IS_SIGN, outputflags);
    addflag(IS_SIG, outputflags);
    addflag(IS_ON_BORDER, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    addflag(SUBBAND_NUM, outputflags);
    addflag(SUBBAND_ORIENTATION, outputflags);
    addflag(REFINE_LEVEL, outputflags);
    addflag(NSIG_NW, outputflags);
    addflag(NSIG_N, outputflags);
    addflag(NSIG_NE, outputflags);
    addflag(NSIG_N, outputflags);
    addflag(NSIG_W, outputflags);
    addflag(NSIG_E, outputflags); 
    addflag(NSIG_SW, outputflags);
    addflag(NSIG_S, outputflags);
    addflag(NSIG_SE, outputflags);
    addflag(NSIG_PARENT, outputflags);
    addflag(NSIG_CHILDREN, outputflags);
    addflag(NSIG_DESCENDANTS, outputflags);
    addflag(NSIG_PARENT, outputflags);
    addflag(NSIG_SL1, outputflags);
    addflag(NSIG_SL2, outputflags);
    addflag(NSIGN_N, outputflags);
    addflag(NSIGN_S, outputflags);
    addflag(NSIGN_E, outputflags);
    addflag(NSIGN_W, outputflags);
    addflag(SIG_H, outputflags);
    addflag(SIG_V, outputflags);
    addflag(SIG_D, outputflags);
    addflag(SIG_LABEL, outputflags);
    addflag(SIGN_HS, outputflags);
    addflag(SIGN_VS, outputflags);
    addflag(SIGN_LABEL, outputflags);
    addflag(REFINE_LABEL, outputflags);
    addflag(SIG_COUNT, outputflags);
    return 0;
  case 8: // GTW-like set, take 2
    addflag(IS_SIGN, outputflags);
    addflag(IS_REFINE, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    addflag(REVERSE_SUBBAND_LEVEL, outputflags);
    addflag(SIG_COUNT_GTW, outputflags);
    return 0;
  case 9:  // add debugging info for set 10, then fall through
    addflag(SUBBAND_ROW, outputflags);
    addflag(SUBBAND_COL, outputflags);    
    addflag(SUBBAND_NUM, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    CharacteristicType = 10; // purposely continue..
  case 10: //all color flags
  case 11: // nsig_comp color flags
  case 12: // component_num color flags
    return addColorCharacteristicSet(CharacteristicType-10,outputflags);
  case 13: case 14: case 15: case 16: // future color flag expansion slots
    return addColorCharacteristicSet(CharacteristicType-10,outputflags);
  case 19: // complete GTW & jp2k characteristics.
    addflag(SIGN_LABEL, outputflags);
    addflag(REFINE_LABEL, outputflags); 
  case 18: // extended significance test using both GTW and JP2k like. 
    addflag(IS_SIGN, outputflags);
    addflag(IS_REFINE, outputflags);
  case 17: // significance test using both GTW and JP2k like. 
    addflag(IS_SIG, outputflags);
    addflag(BITPLANE_NUM, outputflags);
    addflag(SUBBAND_NUM, outputflags);
    addflag(SIG_COUNT_GTW, outputflags);
    addflag(SIG_LABEL, outputflags);
    return 0;
  default:
   QccErrorAddMessage("(getCharacteristicSet): Unsupported characteristic type %d", CharacteristicType);
   return (1);   
  }
}


static int numtokens(char *line, int *first) {
  while ((*line)==' ') line++;
  if ((*line=='(')) {line++;
  }
  (*first)=  strtol(line, NULL, 10);
  int count = 0; 
  while ((*line)!='\0') {
    line++;
    if ((*line == ' ')) {
      count++;
      while ((*line)==' ') line++;      
    }
  }
  count++;
  return count;
}

int DEBUG = 0;

static void printCharacteristic(const Characteristic *c) {
  printf("  name: %s\n", c->name);
  printf("  description: %s\n", c->description);
  printf("  ccdline: %s", c->ccdline);
  printf("  f: %d\n", (int) c->f);
  printf("  numvalues: %d\n", c->numvalues);
  printf("  valuestart: %d\n", c->valuestart);
}

static void SetCharacteristic(int index, 
			      char *n, 
			      char *desc,
			      char *ccd, 
			      int (*func)(const SubbandComponent *, int cn, const NeighborSignificance *, 
					   const NeighborSigns *, int, int, int, int)  
			      ) {
  int firstval;
  AllC[index].name = n;
  AllC[index].description = desc;
  AllC[index].ccdline = ccd;
  AllC[index].f = func;
  AllC[index].numvalues = numtokens(ccd, &firstval);
  AllC[index].valuestart = firstval;

  if (DEBUG) {
    printf("AllC[%d] == \n", index);
    printCharacteristic(&AllC[index]);
  }
}

// define methods to be stored as function pointers. 
static int bitplane_num_f(
			  const SubbandComponent *sc, int cn, 
			  const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return bitplane_num(&sc[cn].sub[sb], r, c, bp);
}

static int is_sign_f(
		     const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
		     const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return is_sign(&sc[cn].sub[sb], r, c, bp);
}

static int is_sig_f(
		    const SubbandComponent *sc, int cn,  const NeighborSignificance *ns1, 
		    const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return is_sig(&sc[cn].sub[sb], r, c, bp);
}
static int n_sig_01_f(
		      const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->n > 0;
}		       

static int is_on_border_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return is_on_border(&sc[cn].sub[sb], r, c);
}

static int subband_orientation_f(
				 const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return subband_orientation(sb);
}
static int refine_level_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return refine_level(&sc[cn].sub[sb], r, c, bp);
}
static int is_refine_f(
		       const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return is_refine(&sc[cn].sub[sb], r, c, bp);
}
static int nsig_nw_f(
		     const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->nw;
}
static int nsig_n_f(
		    const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->n;
}
static int nsig_ne_f(
		     const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->ne;
}
static int nsig_w_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->w;
}
static int nsig_e_f(
			  const SubbandComponent *sc,  int cn,const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->e;
}
static int nsig_sw_f(
			  const SubbandComponent *sc,  int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->sw;
}
static int nsig_s_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->s;
}
static int nsig_se_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->se;
}
static int nsig_children_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->children;
}
static int nsig_descendants_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->descendants;
}
static int nsig_parent_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->parent;
}
static int nsig_sl1_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->sl1;
}
static int nsig_sl2_f(
			  const SubbandComponent *sc,  int cn,const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns1->sl2;
}
static int nsign_n_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns2->n;
}
static int nsign_s_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns2->s;
}
static int nsign_e_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns2->e;
}
static int nsign_w_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return ns2->w;
}
static int subband_num_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sb;
}
static int reverse_subband_level_f(
			  const SubbandComponent *sc,  int cn,const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return -(sb+2)/3;
}
static int subband_row_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return r;
}
static int subband_col_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return c;
}
static int sig_h_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sig_h(ns1);
}
static int sig_v_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sig_v(ns1);
}
static int sig_d_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sig_d(ns1);
}
static int sig_label_f(
			  const SubbandComponent *sc,  int cn,const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sig_label(ns1);
}
static int sign_hs_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sign_hs(ns2);
}
static int sign_vs_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sign_vs(ns2);
}
static int sign_label_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sign_label(ns2);
}
static int refine_label_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return refine_label(ns1,&(sc[cn].sub[sb]), r, c, bp);
}
static int sig_count_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return sig_count(ns1);
}

static int component_num_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return cn;
}

static int nsig_comp0_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  if (bp==-1) {
    bp = sc[cn].sub[sb].coeff[r][c].significance_level;
  }
  int x = getNeighborSignificance(&sc[0].sub[sb],r,c,bp);
  if (x ==0) {
    printf("nsig_comp0_f: color component neighbor not found; serious error\n");
    exit(1);
  }
  return x;
}
static int nsig_comp1_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  if (bp==-1) {
    bp = sc[cn].sub[sb].coeff[r][c].significance_level;
  }                          
  int x= getNeighborSignificance(&sc[1].sub[sb],r,c,bp);
  if (x ==0) {
    printf("nsig_comp1_f: color component neighbor not found; serious error\n");
    exit(1);
  }
  return x;
}
static int nsig_comp2_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  if (bp==-1) {
    bp = sc[cn].sub[sb].coeff[r][c].significance_level;
  }
  int x= getNeighborSignificance(&sc[2].sub[sb],r,c,bp);
  if (x ==0) {
    printf("nsig_comp2_f: color component neighbor not found; serious error\n");
    exit(1);
  }
  return x;
}

static int nbitval_comp0_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return bit_value_causal(&sc[0].sub[sb],r,c,bp);
}
static int nbitval_comp1_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return bit_value_causal(&sc[1].sub[sb],r,c,bp);
}
static int nbitval_comp2_f(
			  const SubbandComponent *sc, int cn, const NeighborSignificance *ns1, 
			  const NeighborSigns *ns2, int r, int c, int sb, int bp) {
  return bit_value_causal(&sc[2].sub[sb],r,c,bp);
}


Characteristic AllC[128];

void InitAllC(int numsubbands ,int numbitplanes){
  static int done = 0;
  char *bitplanenumccd;
  char *subbandnumccd;
  char *subbandlevelccd;
  char *revsubbandlevelccd;
  if (numbitplanes <= 0 ) numbitplanes = 20;
  bitplanenumccd= malloc(sizeof( char)*numbitplanes*3); // allocate enough space for these. 
  subbandnumccd = malloc(sizeof (char) * numsubbands*3);
  subbandlevelccd = malloc(sizeof (char) * numsubbands*3);
  revsubbandlevelccd = malloc(sizeof (char) * numsubbands*3);
  if (bitplanenumccd == NULL || subbandnumccd == NULL) {
    printf("InitAllC: error allocating memory\n");
    return;
  }

  int i;
  char temp[5];
  strcpy(bitplanenumccd, "0");
  for (i=1; i < numbitplanes; i++) {
    sprintf(temp, " %d", i);
    strcat(bitplanenumccd, temp);
  }
  strcat(bitplanenumccd, "\n");

  strcpy(subbandnumccd, "0");
  strcpy(subbandlevelccd, "0");
  for (i=1; i < numsubbands; i++) {
    sprintf(temp, " %d", i);
    strcat(subbandnumccd, temp);
    if (i <= numsubbands/3) {
      strcat(subbandlevelccd, temp);
    }
  }
  strcat(subbandnumccd, "\n");
  strcat(subbandlevelccd, "\n");

  revsubbandlevelccd[0]='\0';
  for (i=-(numsubbands/3); i < 0; i++) {
    sprintf(temp, "(%d) ", i);
    strcat(revsubbandlevelccd, temp );
  }
  strcat(revsubbandlevelccd, "0\n");

  if (done ==1) {
    // replacing bitplane and subband, free old stings
    free(AllC[SUBBAND_NUM].ccdline);
    free(AllC[BITPLANE_NUM].ccdline);
    free(AllC[REVERSE_SUBBAND_LEVEL].ccdline); // REFINE_LEVEL's ccdline is shared with BITPLANE_NUM's

  }

     SetCharacteristic(
		      BITPLANE_NUM, 
		      "Bit_plane_number",
		      "bitplane number in which this bits gets processed (for signs, bitplanenum== bitplane in which the coeff becomes significant", 
		      bitplanenumccd,
		      &bitplane_num_f);
    SetCharacteristic(
		      SUBBAND_NUM, 
		      "Subband_number",
		      "",
		      subbandnumccd,
		      &subband_num_f);
    SetCharacteristic(
		      REFINE_LEVEL, 
		      "refine_level", 
		      "1 for first refinement bit, i for ith refinement bit, cannot go negative." ,
		      bitplanenumccd, 
		      refine_level_f);


    SetCharacteristic(
		      REVERSE_SUBBAND_LEVEL, 
		      "reverse_subband_level", 
		      "reverse_subband level (not num subbands)",
		      revsubbandlevelccd, 
		      reverse_subband_level_f);

    if (!done) {
    SetCharacteristic(
		      SUBBAND_ORIENTATION, 
		      "Subband_orientation",
		      "",
		      "0 1 2 3\n", 
		      &subband_orientation_f);
    SetCharacteristic(
		      IS_SIGN, 
		      "is_sign_bit(x)",
		      "1 if x represents a sign bit, 0 otherwise",
		      "0 1\n",
		      &is_sign_f);
    SetCharacteristic(
		      IS_SIG, 
		      "is_significance_bit", 
		      "is bit processed is significant pass",
		      "0 1\n",
		      &is_sig_f);
    SetCharacteristic(
		      NSIG_N_01, 
		      "is_N_significant", 
		      "1 if N exists and is significant, 0 otherwise",
		      "0 1\n",
		      &n_sig_01_f);
    SetCharacteristic(
		      IS_ON_BORDER, 
		      "is_on_border", 
		      "is part of coeff on edge of subband",
		      "0 1\n", 
		      is_on_border_f);
    SetCharacteristic(
		      IS_REFINE, 
		      "is_refinement_bit", 
		      "1 if bit is processed in refinement pass",
		      "0 1\n", 
		      is_refine_f);
    SetCharacteristic(
		      NSIG_N, 
		      "N_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_n_f);
    SetCharacteristic(
		      NSIG_NW, 
		      "NW_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_nw_f);
    SetCharacteristic(
		      NSIG_NE, 
		      "NE_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_ne_f);
    SetCharacteristic(
		      NSIG_W, 
		      "W_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_w_f);
    SetCharacteristic(
		      NSIG_E, 
		      "E_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => (not possible), 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_e_f);
    SetCharacteristic(
		      NSIG_SE, 
		      "SE_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => (not possible), 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_se_f);
    SetCharacteristic(
		      NSIG_S, 
		      "S_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => (not possible), 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_s_f);
    SetCharacteristic(
		      NSIG_SW, 
		      "SW_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => (not possible), 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_sw_f);
    SetCharacteristic(
		      NSIG_PARENT, 
		      "Parent_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_parent_f);
    SetCharacteristic(
		      NSIG_CHILDREN, 
		      "children_significance", 
		      "-1 => insig, 0 => no children, 1 => (not possible), 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_children_f);
    SetCharacteristic(
		      NSIG_DESCENDANTS, 
		      "Descendants_significance", 
		      "-1 => insig, 0 => no children, 1 => (not possible), 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_descendants_f);
    SetCharacteristic(
		      NSIG_SL1, 
		      "SL1_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => (if sl1 causally precedes) became sig in current bitplane, 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_sl1_f);
    SetCharacteristic(
		      NSIG_SL2, 
		      "SL2_significance", 
		      "-1 => insig, 0 => doesn't exist, 1 => (if sl2 causally precedes) became sig in current bitplane, 2-> became sig in prev bitplane",
		      "(-1) 0 1 2\n", 
		      nsig_sl2_f);
    SetCharacteristic(
		      NSIGN_N, 
		      "N_sign_value", 
		      "positive, negative, or zero; zero => N is insig at current bitplane",
		      "(-1) 0 1\n", 
		      nsign_n_f);
    SetCharacteristic(
		      NSIGN_S, 
		      "S_sign_value", 
		      "positive, negative, or zero; zero => S is insig at previous bitplane",
		      "(-1) 0 1\n", 
		      nsign_s_f);
    SetCharacteristic(
		      NSIGN_W, 
		      "W_sign_value", 
		      "positive, negative, or zero; zero => W is insig at current bitplane",
		      "(-1) 0 1\n", 
		      nsign_w_f);
    SetCharacteristic(
		      NSIGN_E, 
		      "E_sign_value", 
		      "positive, negative, or zero; zero => E is insig at previous bitplane",
		      "(-1) 0 1\n", 
		      nsign_e_f);
    SetCharacteristic(
		      SIG_H, 
		      "significance_h_value", 
		      "# of significant horizontal neighbors (vertical neighbors in orientaion 2 subs)",
		      "0 1 2\n", 
		      sig_h_f);
    SetCharacteristic(
		      SIG_V, 
		      "significance_V_value", 
		      "# of significant vertical neighbors (horizontal neighbors in orientaion 2 subs)",
		      "0 1 2\n", 
		      sig_v_f);
    SetCharacteristic(
		      SIG_D, 
		      "significance_D_value", 
		      "# of significant diagonal neighbors",
		      "0 1 2 3 4\n", 
		      sig_d_f);

    SetCharacteristic(
		      SIG_LABEL, 
		      "significance_label", 
		      "signifcance label, as in EBCOT/JPEG2000; depends on neighborhood significance",
		      "0 1 2 3 4 5 6 7 8\n", 
		      sig_label_f);

    SetCharacteristic(
		      SIGN_HS, 
		      "sign_H_value", 
		      "-1, 0, or 1 depending on the sign of the quanitity (sum of signs of H Neighbors) (use V-neighbors in orientation 2 subbands)",
		      "(-1) 0 1\n", 
		      sign_hs_f);
    SetCharacteristic(
		      SIGN_VS, 
		      "sign_V_value", 
		      "-1, 0, or 1 depending on the sign of the quanitity (sum of signs of V Neighbors) (use H-neighbors in orientation 2 subbands)",
		      "(-1) 0 1\n", 
		      sign_vs_f);

    SetCharacteristic(
		      SIGN_LABEL, 
		      "sign_label_prediction", 
		      "ebcot's sign_label * sign_prediction value; depends on sign_HS and sign_VS",
		      "(-4) (-3) (-2) (-1) 0 1 2 3 4\n", 
		      sign_label_f);

    SetCharacteristic(
		      REFINE_LABEL, 
		      "magnitude_refinement_label", 
		      "refinement pass label, as given in EBCOT/JPEG2000, depends on refinement_level & signeighbors",
		      "0 1 2\n", 
		      refine_label_f);


    SetCharacteristic(
		      SIG_COUNT, 
		      "significance_neighbor_count", 
		      "Count of number of significant neighbors, like GTW",
		      "0 1 2 3 4 5 6 7 8 9 10 11 12\n", 
		      sig_count_f);

    SetCharacteristic(
		      SIG_COUNT_GTW, 
		      "significance_neighbor_count", 
		      "Count of number of significant neighbors, like GTW",
		      "0 1 2 3+\n", 
		      sig_count_f);

    SetCharacteristic(
		      COMPONENT_NUM, 
		      "component_num", 
		      "Component number (for color images)",
		      "0 1 2\n", 
		      component_num_f);

    SetCharacteristic(
		      NSIG_COMP0, 
		      "Comp0_significance", 
		      "-1 => insig, 0=> cannot occur, 1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "0- 1 2\n", 
		      nsig_comp0_f);

    SetCharacteristic(
		      NSIG_COMP1, 
		      "Comp1_significance", 
		      "-1 => insig, 0=> cannot occur,  1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "0- 1 2\n", 
		      nsig_comp1_f);

    SetCharacteristic(
		      NSIG_COMP2, 
		      "Comp2_significance", 
		      "-1 => insig, 0=> cannot occur,  1 => became sig in current bitplane, 2-> became sig in prev bitplane",
		      "0- 1 2\n", 
		      nsig_comp2_f);

    SetCharacteristic(
		      NBITVAL_COMP0, 
		      "Comp0_bitval", 
		      "bit value of component 0 neighbor at current bitplane; -1 => unknown",
		      "(-1) 0 1\n", 
		      nbitval_comp0_f);

    SetCharacteristic(
		      NBITVAL_COMP1, 
		      "Comp1_bitval", 
		      "bit value of component 1 neighbor at current bitplane; -1 => unknown",
		      "(-1) 0 1\n", 
		      nbitval_comp1_f);

    SetCharacteristic(
		      NBITVAL_COMP2, 
		      "Comp2_bitval", 
		      "bit value of component 2 neighbor at current bitplane; -1 => unknown",
		      "(-1) 0 1\n", 
		      nbitval_comp2_f);
                      
    SetCharacteristic(
		      SUBBAND_ROW, 
		      "row", 
		      "row of pixel, used for debugging; ccd is invalid", 
		      "invalid ccd\n", 
		      subband_row_f);
    SetCharacteristic(
		      SUBBAND_COL, 
		      "col", 
		      "col of pixel, used for debugging; ccd is invalid", 
		      "invalid ccd\n", 
		      subband_col_f);
  }
  done = 1; 
}


